﻿using JinYuan.Helper;
using JinYuan.Models;
using JinYuan.VirtualDataLibrary;
using Language;
using MiniExcelLibs;
using PLC;
using PLC.PLCAlarm;
using PLCCommunication;
using PLCCommunication.Common;
using PLCCommunication.Common.DataConvert;
using SqlSugar;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using DataType = PLC.DataType;


namespace JinYuan.ControlCenters
{
    public partial class ControlCenter : IDisposable
    {
        private static readonly object uiLock = new object();
        private static ControlCenter _instance;
        public static ControlCenter Instance
        {
            get
            {
                lock (uiLock)
                {
                    return _instance ??= new ControlCenter();
                }
            }
        }

        private readonly Dictionary<string, PlcGroup> groups = new Dictionary<string, PlcGroup>();
        private Dictionary<string, Func<JYResult<byte[]>, PlcGroup, Task>> stationFunctions;
        //private Dictionary<string, Action<JYResult<byte[]>, PlcGroup>> stationFunctions;
        private readonly Dictionary<PlcReadWriteBase, List<PlcDevice>> plcDeviceMapping = new Dictionary<PlcReadWriteBase, List<PlcDevice>>();
        private readonly Dictionary<string, Task> groupTasks = new Dictionary<string, Task>();
        private readonly Dictionary<PlcReadWriteBase, PLCAlarmReader> plcAlarmReaders = new Dictionary<PlcReadWriteBase, PLCAlarmReader>();

        public CancellationTokenSource _cts;
        private Task _heartbeatTask;
        private const int HeartbeatInterval = 1000; // 1 second

        /// <summary>
        /// 定时器-定时刷新状态和数据
        /// </summary>
        private System.Timers.Timer Timer_RefreshData;

        private readonly string configFolderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config");

        private ControlCenter()
        {
            _cts = new CancellationTokenSource();

            if (CommonMethods.plcDevices == null)
            {
                CommonMethods.plcDevices = new List<PlcReadWriteBase>();
            }
            InitializeDevicesFromExcel();
            GetAlarmData();
            InitFunc();

            Timer_RefreshData = new System.Timers.Timer(1000);
            Timer_RefreshData.Elapsed += Timer_RefreshData_Elapsed;
            Timer_RefreshData.Start();

            // 轴位置监控
            Task.Run(() => { ShowAxleEven_Run(); });

            // 电机位置监控
            //Task.Run(() => { ShowMotorEven_Run(); });

            //Mes心跳监控
            Task.Run(new Action(() => { UpdateMesHeartBeat(); }));

            //删除30天内日志
            //DeleteLog.Start(CommonMethods.strDeletepath);//会把整个ApiLog删除
            string[] clrPath = new string[] { CommonMethods.strAlarmLogspath, CommonMethods.strMesLogspath, CommonMethods.strWattrMeterpath, Application.StartupPath + "\\Logs\\" };
            short[] seltWay = new short[] { 0, 0, 0, 1 };
            DeleteLog.Start(clrPath, seltWay);

            if (!CommonMethods.IsRun)
            {
                CommonMethods.ResetEventRecv.Reset();
            }
        }

        /// <summary>
        /// 初始化 工位方法，添加到字典里面
        /// </summary>
        private void InitFunc()
        {

            stationFunctions = new Dictionary<string, Func<JYResult<byte[]>, PlcGroup, Task>>
            {
                ["电芯进站A"] = FeedingStationA,
               // ["电芯进站B"] = FeedingStationB,
                ["电芯出站A"] = BlankingStationA,
               // ["电芯出站B"] = BlankingStationB,
                //["结构件料盘"] = MaterialStation,
                // 根据需要添加更多站点功能
            };
        }

        public async Task StartAsync()
        {
            CreatePLCThreads();
            _heartbeatTask = StartHeartbeatCheck(_cts.Token);
            await Task.CompletedTask;
        }


        #region PLC
        private void InitializeDevicesFromExcel()
        {
            CommonMethods.AddDataMonitorLog(1, "开始加载配置参数……".Translated());
            string deviceConfigPath = Path.Combine(configFolderPath, "Device.xlsx");
            string groupConfigPath = Path.Combine(configFolderPath, "Group.xlsx");
            string variableConfigPath = Path.Combine(configFolderPath, "Variable.xlsx");
            string plcVariableConfigPath = Path.Combine(configFolderPath, "PLCVariable.xlsx");

            if (!File.Exists(deviceConfigPath) || !File.Exists(groupConfigPath) || !File.Exists(variableConfigPath))
            {
                LogHelper.Instance.WriteError("配置文件不存在");
                return;
            }

            try
            {
                var deviceConfigs = MiniExcel.Query<PlcDevice>(deviceConfigPath).ToList();
                var groupConfigs = MiniExcel.Query<PlcGroup>(groupConfigPath).ToList();
                var variableConfigs = MiniExcel.Query<PlcVariable>(variableConfigPath).ToList();

                var plcVariableConfigs = MiniExcel.Query<PLCGroupVariable>(plcVariableConfigPath).ToList();
                ConcurrentDictionary<string, PLCGroupVariable> PLCVariable = new ConcurrentDictionary<string, PLCGroupVariable>();
                if (plcVariableConfigs.Count > 0)
                {
                    foreach (PLCGroupVariable variable in plcVariableConfigs)
                    {
                        if (variable.VarAddress != null && !variable.VarAddress.Equals(""))
                        {
                            PLCVariable.TryAdd(variable.VarAddress.Trim(), variable);
                        }
                    }
                }
                CommonMethods.PLCVariable = PLCVariable;

                foreach (var deviceConfig in deviceConfigs.Where(d => d.IsActive))
                {
                    IPEndPoint iep = new IPEndPoint(IPAddress.Parse(deviceConfig.IPAddress), deviceConfig.Port);
                    PlcReadWriteBase plc = PLCFactory.CreatePLC(GetPLCTypeEnum(deviceConfig.PLCType), deviceConfig.PlcNum, $"PLC_{deviceConfig.PlcNum}", iep);

                    deviceConfig.Cts = new CancellationTokenSource();
                    deviceConfig.GroupList = groupConfigs
                        .Where(g => g.IsActive && g.PlcNum == deviceConfig.PlcNum)
                        .ToList();

                    foreach (var group in deviceConfig.GroupList)
                    {
                        group.VarList = variableConfigs
                            .Where(v => v.GroupName == group.GroupName && v.PlcNum == deviceConfig.PlcNum)
                            .ToList();
                    }

                    plcDeviceMapping[plc] = new List<PlcDevice> { deviceConfig };
                    CommonMethods.plcDevices.Add(plc);

                    string tmp = AppDomain.CurrentDomain.BaseDirectory;

                    // 初始化 PLCAlarm Reader报警读取
                    var alarmReader = new PLCAlarmReader(
                        Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AlarmConfig.csv"),
                        Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AlarmRecords"),
                        RecordType.RecordWhenFinish,
                        false
                    );

                    //alarmReader.PLCAlarm_New += AlrmReader_PLCAlarm_New;
                    //alarmReader.PLCAlarm_Remove += AlrmReader_PLCAlarm_Remove;
                    //plcAlarmReaders[plc] = alarmReader;

                    //CommonMethods.plcStatuses[plc] = new Dictionary<string, object>
                    //{
                    //    ["OldStatus"] = (short)0,
                    //    ["StatusCount"] = 0,
                    //    ["GuidAlarm"] = string.Empty,
                    //    ["Status"] = new List<bool> { false, false, false, false }
                    //};
                }
            }
            catch (Exception ex)
            {
                LogHelper.Instance.WriteError($"加载配置失败：{ex.Message}");
            }
            CommonMethods.AddDataMonitorLog(1, "配置文件加载完成".Translated());
        }



        #region 创建PLC线程 几个工位就几个线程

        /// <summary>
        /// 按工位读取线程
        /// </summary>
        /// 

        private readonly Dictionary<string, Thread> groupThreads = new Dictionary<string, Thread>();
        private readonly object lockObject = new object();

        private void CreatePLCThreads()
        {
            for (int i = 0; i < CommonMethods.plcDevices.Count; i++)
            {
                var plc = CommonMethods.plcDevices[i];
                if (plcDeviceMapping.TryGetValue(plc, out var plcDevices))
                {
                    foreach (var plcDevice in plcDevices)
                    {
                        foreach (var plcGroup in plcDevice.GroupList.Where(g => g.IsActive))
                        {
                            string threadKey = $"{plcDevice.PlcNum}-{plcGroup.GroupName}";

                            var parameter = (group: plcGroup, plcIndex: i);

                            Thread thread = new Thread(new ParameterizedThreadStart(ReadPLCWorkModel));
                            thread.IsBackground = true;
                            thread.Priority = ThreadPriority.Highest;
                            lock (lockObject)
                            {
                                groupThreads[threadKey] = thread;
                            }
                            thread.Start(parameter);
                        }
                    }
                }
            }
        }
        #endregion

        #region 循环读取PLC工位状态
        /// <summary>
        /// 读取PLC循环工位
        /// </summary>
        /// <param name="plcModel"></param>
        /// 

        private void ReadPLCWorkModel(object parameter)
        {
            if (parameter is ValueTuple<PlcGroup, int> tuple)
            {
                var (group, plcIndex) = tuple;

                while (!_cts.Token.IsCancellationRequested)
                {
                    if (CommonMethods.IsRun)
                    {
                        if (CommonMethods.plcDevices[plcIndex].IsConnected)
                        {
                            try
                            {
                                JYResult<short> OpenValue = CommonMethods.plcDevices[plcIndex].ReadValue<JYResult<short>>(group.VarList[0].VarAddress, DataType.Short);

                                if (OpenValue.IsSuccess && OpenValue.Content == 1)
                                {
                                    JYResult<byte[]> resByte = CommonMethods.plcDevices[plcIndex].ReadValue<JYResult<byte[]>>($"{group.VarList[2].VarAddress}",
                                        DataType.ArrByte, Convert.ToUInt16(group.VarList[2].OffsetOrLength));

                                    CommonMethods.plcDevices[plcIndex].WriteInt16(group.VarList[0].VarAddress, (short)0);

                                    if (resByte != null && stationFunctions.TryGetValue(group.GroupName, out var action))
                                    {
                                        Task.Run(() => action(resByte, group));
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                LogHelper.Instance.WriteError($"错误: {group.GroupName} - {ex.Message}");
                            }
                        }
                    }
                    Thread.Sleep(50);
                }
            }
        }
        #endregion


        #region 开始停止联机事件
        /// <summary>
        /// 开始联机
        /// </summary>
        /// <returns></returns>

        public async Task<bool> ConnectAllPlcsAsync()
        {
            bool allConnected = true;
            if (CommonMethods.plcDevices.Count <= 0)
            {
                CommonMethods.AddDataMonitorLog(1, "无PLC配置信息".Translated() + "，" + "请检查配置文件".Translated());
                return allConnected = false;
            }
            foreach (var plc in CommonMethods.plcDevices)
            {
                if (plcDeviceMapping.TryGetValue(plc, out var plcDevices))
                {
                    foreach (var deviceConfig in plcDevices)
                    {
                        string msg = "";
                        try
                        {
                            // 使用 Task.Run 来在后台线程执行连接操作
                            bool isConnected = await Task.Run(() =>
                            {
                                // 设置一个连接超时
                                using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10))) // 10秒超时
                                {
                                    try
                                    {
                                        return plc.Connect(ref msg);
                                    }
                                    catch (OperationCanceledException)
                                    {
                                        msg = "连接超时";
                                        return false;
                                    }
                                }
                            });

                            deviceConfig.IsConnected = isConnected;

                            if (!deviceConfig.IsConnected)
                            {
                                allConnected = false;
                                LogHelper.Instance.WriteLog($"连接PLC失败: {deviceConfig.PlcNum}, 错误: {msg}");
                                CommonMethods.AddDataMonitorLog(1, "连接PLC失败".Translated() + $": {deviceConfig.PlcNum}, " + "错误".Translated() + $": {msg}");
                            }
                            else
                            {
                                CommonMethods.AddDataMonitorLog(0, "成功连接PLC".Translated() + $": {deviceConfig.PlcNum}");
                            }
                        }
                        catch (Exception ex)
                        {
                            allConnected = false;
                            LogHelper.Instance.WriteLog($"连接PLC时发生异常: {deviceConfig.PlcNum}, 错误: {ex.Message}");
                            CommonMethods.AddDataMonitorLog(2, "连接PLC时发生异常".Translated() + $": {deviceConfig.PlcNum}" + "错误".Translated() + $": {ex.Message}");
                        }
                    }
                }
            }
            return allConnected;
        }

        /// <summary>
        /// 断开链接
        /// </summary>
        public void DisconnectAllPlcs()
        {
            foreach (var plc in CommonMethods.plcDevices)
            {
                if (plcDeviceMapping.TryGetValue(plc, out var plcDevices))
                {
                    foreach (var deviceConfig in plcDevices)
                    {
                        plc.Disconnect();
                        deviceConfig.IsConnected = false;
                        CommonMethods.AddDataMonitorLog(0, "已断开与PLC".Translated() + $"[{deviceConfig.PlcNum}]");
                    }
                }
            }
        }
        #endregion

        #endregion

        #region MES
        /// <summary>
        /// Mes心跳
        /// </summary>
        private void UpdateMesHeartBeat()
        {
            Thread.Sleep(100);
            while (true)//true
            {
                try
                {
                    if (CommonMethods.mesConfig.IsLoginMesOK && CommonMethods.IsRun)//CommonMethods.mesConfig.isUpMes && 
                    {
                        if (Ping() == true)
                        {
                            CommonMethods.mesConfig.isConnected = true;
                        }
                        else//Ping失败，提示检查线路。
                        {
                            CommonMethods.mesConfig.isConnected = false;
                            if (DateTime.Now.Second % 10 == 0)
                            {
                                string errStr = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")},Mes心跳Ping失败,IP:{CommonMethods.mesConfig.MESURLAddressIP},端口号:{CommonMethods.mesConfig.MESURLAddressPort}";
                                TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{DateTime.Now.ToString("yyyyMMdd")}\Mes心跳报警\{DateTime.Now.ToString("HH")}.txt", errStr);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    string errStr = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")},Mes心跳Ping异常,IP:{CommonMethods.mesConfig.MESURLAddressIP},端口号:{CommonMethods.mesConfig.MESURLAddressPort},原因:{ex.ToString()}";
                    TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{DateTime.Now.ToString("yyyyMMdd")}\Mes心跳报警\{DateTime.Now.ToString("HH")}.txt", errStr);
                }
                Thread.Sleep(1000);
            }
        }

        /// <summary>
        /// Ping 检查网络线路问题
        /// </summary>
        /// <returns></returns>
        public bool Ping()
        {
            try
            {
                string strIP = CommonMethods.mesConfig.MESURLAddressIP;
                int port = Convert.ToInt32(CommonMethods.mesConfig.MESURLAddressPort);
                IPAddress ip = IPAddress.Parse(strIP);
                IPEndPoint _endPoint = new IPEndPoint(ip, port);

                if (_endPoint.Address == null)
                {
                    return false;
                }

                Ping _ping = new Ping();
                int timeout = 1000;
                PingReply mPingRcv = _ping.Send(_endPoint.Address, timeout);
                return (mPingRcv.Status == IPStatus.Success) ? true : false;
            }
            catch (Exception ex)
            {
                string errStr = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")},Mes心跳Ping异常,IP:{CommonMethods.mesConfig.MESURLAddressIP},端口号:{CommonMethods.mesConfig.MESURLAddressPort},原因:{ex.ToString()}";
                TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{DateTime.Now.ToString("yyyyMMdd")}\Mes心跳报警\{DateTime.Now.ToString("HH")}.txt", errStr);
                return false;
            }

        }
        #endregion

        #region 4、心跳和状态检查
        /// <summary>
        /// 心跳检测
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        private async Task StartHeartbeatCheck(CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                if (CommonMethods.IsRun)
                {
                    foreach (var plc in CommonMethods.plcDevices)
                    {
                        if (plcDeviceMapping.TryGetValue(plc, out var plcDevices))
                        {
                            foreach (var plcDevice in plcDevices)
                            {
                                if (plcDevice.IsActive && plcDevice.IsHeartBeat)
                                {
                                    await CheckHeartbeatForDevice(plc, plcDevice);
                                    //await ShowStateEven_RunAsync();
                                }
                            }
                        }
                    }
                }
                await Task.Delay(HeartbeatInterval, cancellationToken);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="plc"></param>
        /// <param name="plcDevice"></param>
        /// <returns></returns>
        private async Task CheckHeartbeatForDevice(PlcReadWriteBase plc, PlcDevice plcDevice)
        {
            if (plcDevice.IsConnected)
            {
                JYResult result = await Task.Run(() => plc.ReadValue<JYResult<short>>(plcDevice.HeartBeat, DataType.Short));
                if (result.IsSuccess)
                {
                    plcDevice.ErrorTimes = 0;
                    JYResult res = await Task.Run(() => plc.WriteValue(plcDevice.HeartBeat, (short)1, DataType.Short));
                    if (!res.IsSuccess)
                    {
                        plcDevice.IsConnected = false;
                        LogHelper.Instance.WriteLog($"PLC编号：{plcDevice.PlcNum}=心跳写入异常:{res.Message}!!!");
                    }
                }
                else
                {
                    HandleHeartbeatFailure(plcDevice, result);
                }
            }
            else
            {
                await ReconnectDevice(plc, plcDevice);
            }
        }

        private void HandleHeartbeatFailure(PlcDevice plcDevice, JYResult result)
        {
            plcDevice.ErrorTimes++;
            plcDevice.IsConnected = false;
            if (plcDevice.ErrorTimes >= plcDevice.AllowErrorTimes)
            {
                LogHelper.Instance.WriteLog($"编号：[{plcDevice.PlcNum}]的PLC链接断开:{result.Message}");
            }
        }

        private async Task ReconnectDevice(PlcReadWriteBase plc, PlcDevice plcDevice)
        {
            if (!plcDevice.IsFirstConnect)
            {
                await Task.Delay(plcDevice.ReConnectTime);
                plc.Disconnect();
            }
            string msg = "";
            var connectResult = await Task.Run(() => plc.Connect(ref msg));
            plcDevice.IsConnected = connectResult;
            LogHelper.Instance.WriteLog(connectResult
                ? $"PLC编号：{plcDevice.PlcNum}{(plcDevice.IsFirstConnect ? "初次" : "重新")}连接成功{msg}!"
                : $"[{plcDevice.PlcNum}]#PLC{(plcDevice.IsFirstConnect ? "初次" : "重新")}连接失败{msg}!");

            plcDevice.IsFirstConnect = false;
        }

        #endregion

        #region 5、报警处理 ×
        //private async Task CheckAlarmsAsync(PlcReadWriteBase plc, string guidAlarm)
        //{
        //    if (plc == null)
        //    {
        //        CommonMethods.AddDataMonitorLog(2, "PLC 对象为 null".Translated());
        //        return;
        //    }

        //    if (!plc.IsConnected)
        //    {
        //        CommonMethods.AddDataMonitorLog(2, "PLC 未连接".Translated());
        //        return;
        //    }

        //    if (plcAlarmReaders.TryGetValue(plc, out var alarmReader))
        //    {
        //        try
        //        {
        //            JYResult<ushort[]> result = null;

        //            // 使用 Task.Run 和超时机制
        //            var task = Task.Run(() =>
        //            {
        //                try
        //                {
        //                    return plc.ReadValue<JYResult<ushort[]>>("D10000", DataType.ArrUshort, 20);
        //                }
        //                catch (Exception ex)
        //                {
        //                    CommonMethods.AddDataMonitorLog(2, "PLC 读取过程中发生异常".Translated() + $": {ex.Message}");
        //                    return null;
        //                }
        //            });

        //            // 设置5秒超时
        //            if (await Task.WhenAny(task, Task.Delay(5000)) == task)
        //            {
        //                result = await task;
        //            }
        //            else
        //            {
        //                throw new TimeoutException("PLC 读取操作超时");
        //            }

        //            if (result == null)
        //            {
        //                throw new InvalidOperationException("PLC 读取操作返回空结果");
        //            }

        //            if (!result.IsSuccess)
        //            {
        //                throw new InvalidOperationException($"PLC 读取操作失败: {result.Message}");
        //            }

        //            if (result.Content == null)
        //            {
        //                throw new InvalidOperationException("PLC 读取操作返回空内容");
        //            }

        //            ushort[] alarmData = result.Content;

        //            // 使用 alarmData 进行后续操作
        //            bool isAlarming = alarmReader.IsPLCAlarm(10000, 20, alarmData);

        //            if (isAlarming)
        //            {
        //                foreach (var alarm in alarmReader.RecordAlarms)
        //                {
        //                    CommonMethods.AddDataMonitorLog(1, $"当前报警: 代码 {alarm.AlarmCode}, 内容 {alarm.AlarmInfo}, 开始时间 {alarm.StartTime}");
        //                }
        //            }
        //        }
        //        catch (Exception ex)
        //        {
        //            CommonMethods.AddDataMonitorLog(2, $"检查报警时发生错误: {ex.Message}");
        //        }
        //    }
        //    else
        //    {
        //        CommonMethods.AddDataMonitorLog(2, $"未找到 PLC 的报警读取器");
        //    }
        //}

        /// <summary>
        /// 新增报警
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        //private void AlrmReader_PLCAlarm_New(object sender, RecordAlarmDataArgs e)
        //{
        //    Task.Run(() =>
        //    {
        //        CommonMethods.alarmManager.AddAlarm(e);
        //        Debug.WriteLine($"新报警: 代码 {e.AlarmCode}, 内容 {e.AlarmInfo}, 日期 {e.AlarmDate}, 开始时间 {e.StartTime:HH:mm:ss}");
        //    });
        //}

        /// <summary>
        /// 报警结束移除报警
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        //private void AlrmReader_PLCAlarm_Remove(object sender, RecordAlarmDataArgs e)
        //{
        //    Task.Run(() =>
        //    {
        //        CommonMethods.alarmManager.RemoveAlarm(e);
        //        Debug.WriteLine($"报警清除: 代码 {e.AlarmCode}, 内容 {e.AlarmInfo}, 日期 {e.AlarmDate}, 结束时间 {DateTime.Now:HH:mm:ss}");
        //    });
        //}

        #endregion

        #region 6、设备状态检查 ×

        /// <summary>
        /// 设备状态
        /// </summary>
        /// <returns></returns>
        //private async Task ShowStateEven_RunAsync()
        //{
        //    try
        //    {
        //        string Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

        //        foreach (var plc in CommonMethods.plcDevices)
        //        {
        //            if (plcDeviceMapping.TryGetValue(plc, out var plcDevices))
        //            {
        //                foreach (var plcDevice in plcDevices)
        //                {
        //                    if (plcDevice.IsConnected)
        //                    {
        //                        var plcStatus = CommonMethods.plcStatuses[plc];
        //                        bool isUpload = false;
        //                        string deviceStatus = string.Empty;
        //                        string deviceStatusDesc = string.Empty;
        //                        short newStatus = 100;
        //                        newStatus = await Task.Run(() => plc.ReadValue<JYResult<short>>("D10", DataType.Short).Content);

        //                        if (newStatus != 100)
        //                        {
        //                            if (newStatus != (short)plcStatus["OldStatus"])
        //                            {
        //                                // 从 Alert 切换到非 Alert 状态时，上传报警信息
        //                                if ((short)plcStatus["OldStatus"] == 3 && newStatus != 3)
        //                                {
        //                                    await CheckAlarmsAsync(plc, (string)plcStatus["GuidAlarm"]);
        //                                }

        //                                // 只要状态变更，就生成新的 GUID
        //                                plcStatus["GuidAlarm"] = Guid.NewGuid().ToString();

        //                                isUpload = true;
        //                                plcStatus["StatusCount"] = 0;
        //                                plcStatus["OldStatus"] = newStatus;
        //                            }
        //                            else
        //                            {
        //                                plcStatus["StatusCount"] = (int)plcStatus["StatusCount"] + 1;
        //                                if ((int)plcStatus["StatusCount"] >= 5 * 60)
        //                                {
        //                                    isUpload = true;
        //                                    plcStatus["StatusCount"] = 0;
        //                                }
        //                            }

        //                            (deviceStatus, deviceStatusDesc) = newStatus switch
        //                            {
        //                                1 => ("Run", "正常运行"),
        //                                2 => ("Maintain", "停止运行"),
        //                                3 => ("Alert", "故障调试"),
        //                                4 => ("Idle", "闲置待机"),
        //                                _ => (string.Empty, string.Empty)
        //                            };

        //                            plcStatus["Status"] = new List<bool> { newStatus == 1, newStatus == 2, newStatus == 3, newStatus == 4 };
        //                            CommonMethods.Statues = new List<bool> { newStatus == 1, newStatus == 2, newStatus == 3, newStatus == 4 };
        //                            if (newStatus == 3) //报警状态
        //                            {
        //                                await CheckAlarmsAsync(plc, (string)plcStatus["GuidAlarm"]);
        //                            }
        //                            else if (newStatus == 4) //闲置状态
        //                            {
        //                                await ShowStuesEven_Run(Date, (string)plcStatus["GuidAlarm"], plc);
        //                            }

        //                            if (isUpload)
        //                            {
        //                                CommonMethods.AddDataMonitorLog(1, $"PLC[{plcDevice.PlcNum}]状态: {deviceStatusDesc}");
        //                            }
        //                            if (CommonMethods.sysConfig.MesModeSwitching)
        //                            {
        //                                // 上传设备状态信息
        //                                if (CommonMethods.sysConfig.MesModeSwitching && isUpload && (newStatus == 1 || newStatus == 3 || newStatus == 4))
        //                                {
        //                                    var (success, message) = await CommonMethods.hbgMes.UploadEquStatusAsync(
        //                                        CommonMethods.mesConfig.DeviceStatus,
        //                                        CommonMethods.mesConfig.siteCode,
        //                                        CommonMethods.mesConfig.lineCode,
        //                                        CommonMethods.mesConfig.equipNum,
        //                                        CommonMethods.mesConfig.MaterialCode,
        //                                        CommonMethods.mesConfig.mesUserName,
        //                                        strGuidAlarm, // RUN 状态时传空
        //                                        deviceStatus,
        //                                        null
        //                                    );

        //                                    if (success)
        //                                    {
        //                                        StatuesCount = 0;
        //                                    }
        //                                }
        //                            }
        //                        }
        //                    }
        //                }
        //            }
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        await Task.Run(() => LogHelper.Instance.WriteEX(ex));
        //    }
        //}


        /// <summary>
        /// HMI手动触摸屏状态
        /// </summary>
        /// <param name="Date"></param>
        /// <param name="strGuid"></param>
        /// <param name="plc"></param>
        /// <returns></returns>
        //private async Task ShowStuesEven_Run(string Date, string strGuid, PlcReadWriteBase plc)
        //{
        //    if (plc.IsConnected)
        //    {
        //        string strCode = "";
        //        string strText = "";
        //        short HMIStatus = await Task.Run(() => plc.ReadValue<JYResult<short>>("D40", DataType.Short).Content);

        //        if (HMIStatus != 0)
        //        {
        //            CommonMethods.AddDataMonitorLog(1, "触发了手动HMI弹窗功能！");
        //            (strCode, strText) = HMIStatus switch
        //            {
        //                1 => ("B1", "计划维保"),
        //                2 => ("B2", "无生产计划"),
        //                3 => ("B3", "样品、试产"),
        //                4 => ("B4", "其他计划停机"),
        //                5 => ("D1", "设备故障"),
        //                6 => ("D2", "设备转型"),
        //                7 => ("D3", "工程变更"),
        //                8 => ("D4", "MES停机"),
        //                9 => ("D5", "品质异常"),
        //                10 => ("D6", "配件、物料更换"),
        //                11 => ("D7", "来料不良"),
        //                12 => ("D8", "待料"),
        //                13 => ("D9", "品质检查"),
        //                14 => ("D10", "清洁点检"),
        //                15 => ("D11", "环境不满足"),
        //                16 => ("D12", "其它非计划停机"),
        //                _ => (string.Empty, string.Empty)
        //            };

        //            if (!string.IsNullOrEmpty(strCode))
        //            {
        //                CommonMethods.AddDataMonitorLog(1, $"{strCode} {strText}");
        //            }


        //            if (CommonMethods.sysConfig.MesModeSwitching)
        //            {
        //                List<AlarmData> alarmObj = new List<AlarmData>();
        //                AlarmData alarmData = new AlarmData();
        //                alarmData.AlarmCode = strCode;
        //                alarmData.StartTime = "";
        //                alarmData.EndTime = "";
        //                alarmData.AlarmType = "非计划损失";
        //                alarmData.AlarmContent = strText;
        //                alarmObj.Add(alarmData);
        //                //上传报警
        //                var (success, message) = await CommonMethods.hbgMes.UploadEquAlarmAsync(CommonMethods.mesConfig.DeviceAlarm, CommonMethods.mesConfig.siteCode, CommonMethods.mesConfig.lineCode,
        //                               CommonMethods.mesConfig.equipNum, CommonMethods.mesConfig.MaterialCode, CommonMethods.mesConfig.mesUserName, alarmObj, strGuid);
        //                if (success)
        //                    CommonMethods.AddDataMonitorLog(0, $"HMI手动弹窗状态已上传成功,代码：{strCode}");
        //            }
        //            bool IsSuccess = CommonMethods.plcDevices[0].WriteInt16("D40", 0);
        //            if (IsSuccess)
        //                CommonMethods.AddDataMonitorLog(0, $"D40已复位0");

        //        }
        //    }
        //}

        #endregion

        #region 定时刷新数据

        int TotalNum = 0;
        int TotalNum1 = 0;
        int Regular = 0;
        int JetBeat = 0;
        private void Timer_RefreshData_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (Regular >= 300)
            {
                Task.Run(() =>
                {
                    UploadEquEnergy();//能耗
                    //ReUpProducResultParam();//定时补传
                });
                Regular = 0;
            }
            if (TotalNum > 4)
            {
                GetEnergyDataFormPlc();
                Refresh12HourProdQty();
                GetDefectTypeQty();
                ReadPLCComm();

                GetASqlAlarmData(DateTime.Today, CommonMethods.strClass);
                TotalNum = 0;
            }
            else if (TotalNum == 2)//设备状态读取
            {
                SetClass(); //变更班次
            }

            Task.Run(() =>
            {
                ShowStateEven_Run();
            });

            if (TotalNum1 >= 3600 * 24)
            {
                Task.Run(() =>
                {
                    DeleteFileOfLocal();
                });
                TotalNum1 = 0;
            }

            //电能表心跳
            if (JetBeat > 5)
            {
                if (!CommonMethods.energyMeter.Connected)
                {
                    CommonMethods.energyMeter.SetTCPParams(IPAddress.Parse("192.168.1.25"), 502);
                    CommonMethods.energyMeter.Connect();
                }
                JetBeat = 0;
            }

            JetBeat++;
            TotalNum++;
            TotalNum1++;
            Regular++;
        }
        #endregion

        #region 设备综合信息
        /// <summary>
        /// 读取PLC通用信息
        /// </summary>
        internal void ReadPLCComm()
        {
            if (CommonMethods.plcDevices.Count != 0 && CommonMethods.plcDevices[0].IsConnected)
            {
                Task.Run(() =>
                {
                    UpTotalCount(null);
                });

                CommonMethods.TotalQty = CommonMethods.plcDevices[0].ReadFloat("D15");//生产总数
                CommonMethods.ProOKQty = CommonMethods.plcDevices[0].ReadFloat("D17");//良品总数

                CommonMethods.Ppm = CommonMethods.plcDevices[0].ReadFloat("D13");
                CommonMethods.JiaDL = Convert.ToDouble(CommonMethods.plcDevices[0].ReadFloat("D11").ToString("F2"));

                #region 开机时间/运行时间
                CommonMethods.PlcOpenAndRunTime = GetList<int>(6, 0);
                JYResult<byte[]> resByte = CommonMethods.plcDevices[0].ReadValue<JYResult<byte[]>>($"D50", DataType.ArrByte, 12);
                if (resByte.IsSuccess && resByte.Content.Length >= 24)
                {
                    for (int i = 0; i < CommonMethods.PlcOpenAndRunTimeAdress.Count; i++)
                    {
                        CommonMethods.PlcOpenAndRunTime[i] = IntLib.GetIntFromByteArray(resByte.Content, i * 4, DataFormat.CDAB);//ShortLib.GetShortFromByteArray(resByte.Content, i * 4, DataFormat.CDAB);
                    }
                }
                #endregion
            }

        }
        #endregion

        #region 保存12小时产能数据
        public int totalNum = 0;    // 总数
        public int okNum = 0;       // 良品数

        /// <summary>
        /// 储存数据到数据库
        /// </summary>
        /// <param name="DataCount"></param>
        public void UpTotalCount(int[] DataCount)
        {

            try
            {
                DateTime dateTime = DateTime.Now;
                string strDate = dateTime.ToString("yyyy-MM-dd");

                // 获取当前时间的小时和分钟
                int currentHour = dateTime.Hour;
                int currentMinute = dateTime.Minute;

                // 根据当前分钟确定统计小时
                // 如果当前时间在 X:30 之前，则统计的是前一个小时的数据（从前一个小时的30分到这个小时的29分）
                // 如果当前时间在 X:30 之后，则统计的是当前小时的数据（从当前小时的30分到下个小时的29分）
                int statisticalHour;
                if (currentMinute < 30)
                {
                    statisticalHour = (currentHour + 23) % 24; // 前一个小时，处理跨天的情况
                                                               // 如果是凌晨0点前的数据，需要使用前一天的日期
                    if (currentHour == 0)
                    {
                        strDate = dateTime.AddDays(-1).ToString("yyyy-MM-dd");
                    }
                }
                else
                {
                    statisticalHour = currentHour;
                }

                // 数据有效性验证
                if (statisticalHour < 0 || statisticalHour > 23)
                {
                    throw new ArgumentException($"无效的小时值: {statisticalHour}");
                }

                //读取统计小时的PLC投入总数和产出数
                int ProdCurrAllQty = GetToDayHourQty(statisticalHour, true);
                int ProdCurrOKQty = GetToDayHourQty(statisticalHour, false);

                // 确保数量为非负数
                if (ProdCurrAllQty < 0 || ProdCurrOKQty < 0)
                {
                    LogHelper.Instance.WriteError($"产量不能为负数: 投入={ProdCurrAllQty}, 产出={ProdCurrOKQty}");
                    //throw new ArgumentException($"产量不能为负数: 投入={ProdCurrAllQty}, 产出={ProdCurrOKQty}");
                }

                Hourprod mh = new Hourprod
                {
                    FDate = strDate,
                    FHour = statisticalHour,
                    ProdIn = ProdCurrAllQty,
                    ProdOut = ProdCurrOKQty,
                    TestTime = dateTime,
                    Ppm = (int)CommonMethods.Ppm,
                    JiaDL = Convert.ToDecimal(CommonMethods.JiaDL)
                };

                // 尝试更新记录
                int res = CommonMethods.db.UpdateSingle(
                    mh,
                    it => new Hourprod
                    {
                        ProdIn = mh.ProdIn,
                        ProdOut = mh.ProdOut,
                        TestTime = mh.TestTime,
                        Ppm = mh.Ppm,
                        JiaDL = mh.JiaDL
                    },
                    it => it.FDate == mh.FDate && it.FHour == mh.FHour
                );

                // 如果更新失败（记录不存在），则新增记录
                if (res <= 0)
                {
                    bool addResult = CommonMethods.db.AddReturnBool<Hourprod>(mh);
                    if (!addResult)
                    {
                        LogHelper.Instance.WriteError($"保存小时产能新增记录失败");
                    }
                }

                // 可以添加日志记录成功信息
                // Logger.Log($"成功更新/新增产能数据: 日期={strDate}, 小时={statisticalHour}, 时段={statisticalHour}:30~{(statisticalHour + 1) % 24}:29");
            }
            catch (Exception ex)
            {
                // 这里应该添加错误日志记录
                LogHelper.Instance.WriteEX($"保存小时产能数据失败: ", ex);
            }
        }

        //string strErr = "";
        //DateTime dateTime = DateTime.Now;
        //string strDate = dateTime.ToString("yyyy-MM-dd");
        //int Min = dateTime.Minute;
        //int Hour = dateTime.Hour;
        //if (Min < 30)
        //{
        //    Hour -= 1;
        //}
        //if (dateTime.Hour < 30 && dateTime.Hour == 0)
        //{
        //    Hour = 0;
        //}

        ////读取PLC投入总数
        //int ProdCurrAllQty = GetToDayHourQty(Hour, true);
        ////读取PLC产出数
        //int ProdCurrOKQty = GetToDayHourQty(Hour, false);
        //Hourprod mh = new Hourprod();

        //mh.FDate = strDate;
        //mh.FHour = Hour;
        //mh.ProdIn = ProdCurrAllQty;
        //mh.ProdOut = ProdCurrOKQty;
        //mh.TestTime = DateTime.Now;
        //mh.Ppm = CommonMethods.Ppm;
        //mh.JiaDL = Convert.ToDecimal(CommonMethods.JiaDL);

        ////更新
        //int res = CommonMethods.db.UpdateSingle(mh, it => new Hourprod() { ProdIn = mh.ProdIn, ProdOut = mh.ProdOut, TestTime = DateTime.Now, Ppm = mh.Ppm, JiaDL = mh.JiaDL, },
        //    it => it.FDate == mh.FDate && it.FHour == mh.FHour);
        //if (res <= 0) //更新失败就新增保存
        //{
        //    CommonMethods.db.AddReturnBool<Hourprod>(mh);
        //}




        /// <summary>
        /// 每小时产能读取处理
        /// </summary>
        /// <param name="hour"></param>
        /// <param name="flag"></param>
        /// <returns></returns>
        private int GetToDayHourQty(int hour, bool flag)
        {
            try
            {
                string strAddr = "";

                if (flag)//产出
                {
                    strAddr = "D" + (1040 + hour);
                }
                else//良品数
                {
                    strAddr = "D" + (1070 + hour);
                }
                int ProdNGQty = CommonMethods.plcDevices[0].ReadInt16(strAddr);
                return ProdNGQty;

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "系统异常", MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }
            return 0;
        }

        #endregion

        #region 5、设备状态
        /// <summary>
        /// 定时获取设备状态
        /// </summary>
        /// <param name="mt"></param>
        /// 
        int OldStatues = Convert.ToInt32(IniConfigHelper.ReadIniData("上一次设备状态", "DeviceStatus", "1", CommonMethods.strDeviceStatusPath));//退出程序前设备状态
        int StatuesCount = 0;
        DateTime StatuesBeginTime = DateTime.Now.AddMinutes(-6);
        string strGuidAlarm = IniConfigHelper.ReadIniData("上一次Guid", "DeviceGuid", Guid.NewGuid().ToString(), CommonMethods.strDeviceStatusPath);//退出程序前Guid
        bool run_AlarmMark = false;//特殊情况1标志（运行状态）
        bool run_IdleMark = false;//特殊情况2标志（闲置状态）
        bool isUpIdleAlarm = false;//闲置状态报警信息上传标志
        List<AlarmData> idleAlarmData = new List<AlarmData>();//闲置状态的报警信息

        private async void ShowStateEven_Run()
        {
            try
            {
                if (CommonMethods.plcDevices.Count > 0 && CommonMethods.plcDevices != null)
                {
                    if (CommonMethods.plcDevices[0] != null && CommonMethods.plcDevices[0].IsConnected)
                    {
                        DateTime Date = DateTime.Now;
                        bool isUpload = false;
                        string deviceStatus = string.Empty;
                        string deviceStatusDesc = string.Empty;
                        short NewStatus = CommonMethods.plcDevices[0].ReadInt16("D10");

                        if (NewStatus != 100)
                        {
                            //特殊情况1：运行->报警->……->运行
                            if (NewStatus == 3 && OldStatues == 1) { run_AlarmMark = true; }//第一次进入报警状态
                            if (NewStatus == 1) { run_AlarmMark = false; }//下一次运行状态，置位
                            if (run_AlarmMark) { NewStatus = 3; }//报警状态后下一次运行状态期间一直是报警状态
                            //特殊情况2：运行->闲置->……->运行
                            if (NewStatus == 4 && OldStatues == 1) { run_IdleMark = true; }//第一次进入闲置状态
                            if (NewStatus == 1) { run_IdleMark = false; }//下一次闲置状态，置位
                            if (run_IdleMark) { NewStatus = 4; }//闲置状态后下一次运行状态期间一直是闲置状态

                            //闲置状态结束报警信息上传
                            if (OldStatues == 4 && NewStatus != 4 && isUpIdleAlarm)
                            {
                                _ = UpIdleDataAsync(idleAlarmData, strGuidAlarm);
                            }

                            //设备状态信号灯变量
                            CommonMethods.Statues = new List<bool> { NewStatus == 1, NewStatus == 2, NewStatus == 3, NewStatus == 4 };

                            // 状态切换时生成新的 GUID
                            if (NewStatus != OldStatues)
                            {
                                // 从 Alert 切换到非 Alert 状态时，上传报警信息
                                if (OldStatues == 3 && NewStatus != 3)
                                {
                                    ShowAlarmEven_Run(strGuidAlarm);
                                }

                                // 只要状态变更，就生成新的 GUID
                                strGuidAlarm = Guid.NewGuid().ToString(); // 强制生成新的 GUID

                                isUpload = true;
                                //StatuesCount = 0;
                                OldStatues = NewStatus;
                                StatuesBeginTime = Convert.ToDateTime(Date);

                                //记录最新设备状态和Guid
                                //CommonMethods.UpdateConfig("MES_CONFIG", "DeviceStatus", NewStatus.ToString());// 保存设备状态到xml文件
                                //CommonMethods.UpdateConfig("MES_CONFIG", "Guid", strGuidAlarm);// 保存设备状态到xml文件

                                //CommonMethods.Configxml["MES_CONFIG"]["DeviceStatus"] = NewStatus.ToString(); // 保存设备状态到xml文件
                                //CommonMethods.Configxml["MES_CONFIG"]["Guid"] = strGuidAlarm; // 保存设备状态到xml文件
                                //CommonMethods.WriteXmlFile(CommonMethods.Configxml, CommonMethods.xmlFilePath);

                                IniConfigHelper.WriteIniData("上一次设备状态", "DeviceStatus", NewStatus.ToString(), CommonMethods.strDeviceStatusPath);
                                IniConfigHelper.WriteIniData("上一次Guid", "DeviceGuid", strGuidAlarm, CommonMethods.strDeviceStatusPath);
                            }
                            else
                            {
                                // 同种状态持续 5 分钟时上传状态信息
                                //StatuesCount++;
                                //if (StatuesCount >= 5 * 60)
                                //{
                                //    isUpload = true;
                                //    StatuesCount = 0;
                                //}
                                if (Date.Subtract(StatuesBeginTime).TotalSeconds >= 5 * 60)
                                {
                                    isUpload = true;
                                    StatuesBeginTime = DateTime.Now;
                                }
                            }

                            // 根据状态设置设备状态和描述
                            switch (NewStatus)
                            {
                                case 1:
                                    deviceStatus = "Run";
                                    deviceStatusDesc = "正常运行";
                                    break;
                                case 2://取消
                                    deviceStatus = "Maintain";
                                    deviceStatusDesc = "停止运行";
                                    break;
                                case 3:
                                    deviceStatus = "Alert";
                                    deviceStatusDesc = "故障调试";
                                    // Alert 状态时上传报警信息
                                    ShowAlarmEven_Run(strGuidAlarm);
                                    break;
                                case 4:
                                    deviceStatus = "Idle";
                                    deviceStatusDesc = "闲置待机";
                                    ShowStuesEven_Run(strGuidAlarm);
                                    break;
                            }

                            // 上传设备状态信息
                            if (CommonMethods.sysConfig.MesModeSwitching && CommonMethods.mesConfig.isConnected && isUpload && (NewStatus == 1 || NewStatus == 3 || NewStatus == 4))
                            {
                                var (success, message) = await CommonMethods.hbgMes.UploadEquStatusAsync(
                                    CommonMethods.mesConfig.DeviceStatus,
                                    CommonMethods.mesConfig.siteCode,
                                    CommonMethods.mesConfig.lineCode,
                                    CommonMethods.mesConfig.equipNum,
                                    CommonMethods.mesConfig.MaterialCode,
                                    CommonMethods.mesConfig.mesUserName,
                                    strGuidAlarm, // RUN 状态时传空
                                    deviceStatus,
                                    null
                                );

                                if (success)
                                {
                                    StatuesCount = 0;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.Instance.WriteEX(ex);
            }
        }


        #region 触摸屏弹窗
        private async void ShowStuesEven_Run(string strGuid)
        {
            if (CommonMethods.plcDevices[0].IsConnected)
            {
                string strCode = "";
                string alarmName = "";
                short HMIStatus = CommonMethods.plcDevices[0].ReadInt16("D40");
                if (HMIStatus != 0)
                {
                    CommonMethods.AddDataMonitorLog(0, "触发了手动HMI弹窗功能".Translated());
                    switch (HMIStatus)   //注意：B1-D12都为闲置代码，上传代码是只需上传闲置代码
                    {
                        //case 1://取消
                        //    strCode = "B1";
                        //    alarmName = "计划维保";
                        //    CommonMethods.AddDataMonitorLog(0, "B1 计划维保");

                        //    break;
                        //case 2://取消
                        //    strCode = "B2";
                        //    alarmName = "无生产计划";
                        //    CommonMethods.AddDataMonitorLog(0, "B2 无生产计划");
                        //    break;
                        //case 3://取消
                        //    strCode = "B3";
                        //    alarmName = "样品、试产";
                        //    CommonMethods.AddDataMonitorLog(0, "B3 样品、试产");
                        //    break;
                        //case 4://取消
                        //    strCode = "B4";
                        //    alarmName = "其他计划停机";
                        //    CommonMethods.AddDataMonitorLog(0, "B4.其他计划停机");
                        //    break;
                        case 5:
                            strCode = "D1";
                            alarmName = "设备故障".Translated();
                            CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
                            break;
                        case 6:
                            strCode = "D2";
                            alarmName = "设备转型".Translated();
                            CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
                            break;
                        case 7:
                            strCode = "D3";
                            alarmName = "工程变更".Translated();
                            CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
                            break;
                        case 8:
                            strCode = "D4";
                            alarmName = "MES停机".Translated();
                            CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
                            break;
                        case 9:
                            strCode = "D5";
                            alarmName = "品质异常".Translated();
                            CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
                            break;
                        case 10:
                            strCode = "D6";
                            alarmName = "配件,物料更换".Translated();
                            CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
                            break;
                        case 11:
                            strCode = "D7";
                            alarmName = "来料不良".Translated();
                            CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
                            break;
                        case 12:
                            strCode = "D8";
                            alarmName = "待料".Translated();
                            CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
                            break;
                        case 13:
                            strCode = "D9";
                            alarmName = "品质检查".Translated();
                            CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
                            break;
                        case 14:
                            strCode = "D10";
                            alarmName = "清洁点检".Translated();
                            CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
                            break;
                        case 15:
                            strCode = "D11";
                            alarmName = "环境不满足".Translated();
                            CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
                            break;
                        case 16:
                            strCode = "D12";
                            alarmName = "其它非计划停机".Translated();
                            CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
                            break;
                        default:
                            break;
                    }

                    if (CommonMethods.sysConfig.MesModeSwitching && CommonMethods.mesConfig.isConnected)
                    {
                        List<AlarmData> alarmObj = new List<AlarmData>();
                        AlarmData alarmData = new AlarmData();
                        alarmData.AlarmCode = strCode;
                        alarmData.StartTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                        alarmData.EndTime = "";
                        alarmData.AlarmType = "非计划损失";
                        alarmData.AlarmContent = alarmName;
                        alarmObj.Add(alarmData);

                        //闲置报警上传标志
                        isUpIdleAlarm = true;
                        idleAlarmData.Add(alarmData);

                        //上传报警
                        var (success, message) = await CommonMethods.hbgMes.UploadEquAlarmAsync(CommonMethods.mesConfig.DeviceAlarm, CommonMethods.mesConfig.siteCode, CommonMethods.mesConfig.lineCode,
                                       CommonMethods.mesConfig.equipNum, CommonMethods.mesConfig.MaterialCode, CommonMethods.mesConfig.mesUserName, alarmObj, strGuid);
                        if (success)
                            CommonMethods.AddDataMonitorLog(0, "HMI手动弹窗状态已上传成功,代码".Translated() + $"：{strCode}");
                    }
                    bool IsSuccess = CommonMethods.plcDevices[0].WriteInt16("D40", 0);
                    if (IsSuccess)
                        CommonMethods.AddDataMonitorLog(0, $"D40已复位0".Translated());

                }
            }
        }

        #endregion

        /// <summary>
        /// HMI手动弹窗结束状态上传
        /// </summary>
        /// <param name="idleAlarmDate"></param>
        /// <param name="strGuidAlarm"></param>
        /// <returns></returns>
        private async Task UpIdleDataAsync(List<AlarmData> idleAlarmDate, string strGuidAlarm)
        {
            if (idleAlarmDate.Count == 0) { return; }
            string strCode = "";
            foreach (var item in idleAlarmDate)
            {
                item.EndTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                strCode = item.AlarmCode + ",";
            }
            if (CommonMethods.sysConfig.MesModeSwitching && CommonMethods.mesConfig.isConnected)
            {
                //上传报警
                var (success, message) = await CommonMethods.hbgMes.UploadEquAlarmAsync(CommonMethods.mesConfig.DeviceAlarm, CommonMethods.mesConfig.siteCode, CommonMethods.mesConfig.lineCode,
                               CommonMethods.mesConfig.equipNum, CommonMethods.mesConfig.MaterialCode, CommonMethods.mesConfig.mesUserName, idleAlarmDate, strGuidAlarm);
                if (success)
                    CommonMethods.AddDataMonitorLog(0, "HMI手动弹窗结束状态已上传成功,代码".Translated() + $":{strCode.TrimEnd(',')}");
            }
            idleAlarmData.Clear();
            isUpIdleAlarm = false;
        }

        #endregion

        #region 6、设备报警
        //报警表单数据
        List<AlarmForm> listAlarmForm = null;
        public void GetAlarmData()
        {
            //加载PLC报警文件
            try
            {
                string strFileName = System.Environment.CurrentDirectory + "\\欧姆龙报警寄存器对应表.csv";
                listAlarmForm = CSVHelper<AlarmForm>.ReadCSV<AlarmForm>(strFileName);
            }
            catch (Exception ex)
            {
                MessageBox.Show("加载报警文件失败！");
            }

        }

        /// <summary>
        /// 报警信息读取
        /// </summary>
        /// <param name="mt"></param>
        /// <param name="resByte"></param>
        List<AlarmData> listOld = new List<AlarmData>();
        List<AlarmData> listNew = new List<AlarmData>();
        List<AlarmStatus> listAlarmStatus = null;
        private async void ShowAlarmEven_Run(string strGuidAlarm)
        {
            if (!CommonMethods.IsRun || !CommonMethods.plcDevices[0].IsConnected)
            {
                return;
            }

            try
            {
                // 1. 读取 PLC 报警信息
                var alarmStatusList = ReadAlarmStatusFromPLC();
                if (alarmStatusList == null || listAlarmForm == null)//true
                {
                    return;
                }

                // 2. 解析报警信息并生成新的报警列表
                var newAlarms = ParseAlarmStatus(alarmStatusList, strGuidAlarm);
                if (newAlarms.Count > 0)
                {
                    // 3. 检测新报警并添加到旧报警列表，上传第一次报警信息
                    await DetectNewAlarmsAsync(newAlarms);

                    // 4. 显示新报警信息
                    DisplayAlarmInfo(newAlarms);
                }

                // 5. 检测已取消的报警并处理
                var canceledAlarms = DetectCanceledAlarms(newAlarms);
                if (canceledAlarms.Count > 0)
                {
                    // 6. 记录已取消的报警信息（保存本地）
                    LogCanceledAlarms(canceledAlarms);

                    // 7. 上传已取消的报警信息（报警结束上传一次）
                    await UploadCanceledAlarmsAsync(canceledAlarms, strGuidAlarm);
                }
            }
            catch (Exception ex)
            {
                LogHelper.Instance.WriteEX(ex);
            }
        }

        /// <summary>
        /// 从 PLC 读取报警状态
        /// </summary>
        private List<AlarmStatus> ReadAlarmStatusFromPLC()
        {
            //string Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            //JYResult<byte[]> resByte = CommonMethods.plcDevices[0].ReadValue<JYResult<byte[]>>("D10150", DataType.ArrByte, 5000);

            //if (resByte.IsSuccess && resByte != null)
            //{
            //    int startPlcAddr = 10150; // 读取起始地址
            //    return PLCAlarmParseHelper.OmronFinsByte2Status(startPlcAddr, resByte.Content);
            //}
            string Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            // 读取足够的字节覆盖所有可能的报警地址
            int startAddr = 10150;
            int endAddr = 14750; // 根据实际最大地址调整
            int wordCount = endAddr - startAddr + 1;
            int byteCount = wordCount * 2; // 每个字2字节

            JYResult<byte[]> resByte = CommonMethods.plcDevices[0].ReadValue<JYResult<byte[]>>(
                $"D{startAddr}", DataType.ArrByte, (ushort)byteCount);

            if (resByte.IsSuccess && resByte.Content != null)
            {
                return PLCAlarmParseHelper.OmronFinsByte2Status(startAddr, resByte.Content);
            }

            return null;
        }

        /// <summary>
        /// 解析报警状态并生成新的报警列表
        /// </summary>
        private List<AlarmData> ParseAlarmStatus(List<AlarmStatus> alarmStatusList, string strGuidAlarm)
        {
            string Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

            switch (LanguageManager.LanguageCode)
            {
                case "en"://英语报警信息
                    return alarmStatusList
                        .Where(s => s.Status)
                        .Join(listAlarmForm, s => s.PLCAdress, f => f.PLCAdress, (s, f) => new AlarmData()
                        {
                            AlarmGuid = strGuidAlarm,
                            PLCAdress = s.PLCAdress,
                            AlarmCode = f.AlarmCode,
                            AlarmContent = f.EnAlarmContent == "" ? s.PLCAdress : f.EnAlarmContent,
                            AlarmType = "停机报警",
                            AlarmDesc = f.EnAlarmContent == "" ? s.PLCAdress : f.EnAlarmContent,
                            AlarmState = "1",
                            StartTime = Date,
                            EndTime = "",//Date
                            Flag = 0
                        }).ToList();
                case "hu"://匈牙利语报警信息
                    return alarmStatusList
                        .Where(s => s.Status)
                        .Join(listAlarmForm, s => s.PLCAdress, f => f.PLCAdress, (s, f) => new AlarmData()
                        {
                            AlarmGuid = strGuidAlarm,
                            PLCAdress = s.PLCAdress,
                            AlarmCode = f.AlarmCode,
                            AlarmContent = f.HuAlarmContent == "" ? s.PLCAdress : f.HuAlarmContent,
                            AlarmType = "停机报警",
                            AlarmDesc = f.HuAlarmContent == "" ? s.PLCAdress : f.HuAlarmContent,
                            AlarmState = "1",
                            StartTime = Date,
                            EndTime = "",//Date
                            Flag = 0
                        }).ToList();
                case "ms"://马来语报警信息
                    return alarmStatusList
                        .Where(s => s.Status)
                        .Join(listAlarmForm, s => s.PLCAdress, f => f.PLCAdress, (s, f) => new AlarmData()
                        {
                            AlarmGuid = strGuidAlarm,
                            PLCAdress = s.PLCAdress,
                            AlarmCode = f.AlarmCode,
                            AlarmContent = f.MsAlarmContent == "" ? s.PLCAdress : f.MsAlarmContent,
                            AlarmType = "停机报警",
                            AlarmDesc = f.MsAlarmContent == "" ? s.PLCAdress : f.MsAlarmContent,
                            AlarmState = "1",
                            StartTime = Date,
                            EndTime = "",//Date
                            Flag = 0
                        }).ToList();
                case "zh"://中语报警信息
                default:
                    return alarmStatusList
                        .Where(s => s.Status)
                        .Join(listAlarmForm, s => s.PLCAdress, f => f.PLCAdress, (s, f) => new AlarmData()
                        {
                            AlarmGuid = strGuidAlarm,
                            PLCAdress = s.PLCAdress,
                            AlarmCode = f.AlarmCode,
                            AlarmContent = f.AlarmContent == "" ? s.PLCAdress : f.AlarmContent,
                            AlarmType = "停机报警",
                            AlarmDesc = f.AlarmContent == "" ? s.PLCAdress : f.AlarmContent,
                            AlarmState = "1",
                            StartTime = Date,
                            EndTime = "",//Date
                            Flag = 0
                        }).ToList();
            }
        }

        /// <summary>
        /// 检测新报警并添加到旧报警列表
        /// </summary>
        private async Task DetectNewAlarmsAsync(List<AlarmData> newAlarms)
        {
            foreach (var alarm in newAlarms)
            {
                if (!listOld.Any(o => o.PLCAdress == alarm.PLCAdress))
                {
                    listOld.Add(alarm);

                    // 4.5 新增逻辑（报警开始上传一次）
                    await UploadCanceledAlarmsAsync(newAlarms, strGuidAlarm);
                }
            }
        }

        /// <summary>
        /// 显示报警信息
        /// </summary>
        private void DisplayAlarmInfo(List<AlarmData> newAlarms)
        {
            StringBuilder sb = new StringBuilder();
            newAlarms.ForEach(r => sb.Append($"{r.AlarmContent}          "));

            if (sb.Length > 0)
            {
                CommonMethods.SlideAlarmText = sb.ToString().Substring(0, sb.Length - 10);
            }
        }

        /// <summary>
        /// 检测已取消的报警
        /// </summary>
        private List<AlarmData> DetectCanceledAlarms(List<AlarmData> newAlarms)
        {
            var canceledAlarms = new List<AlarmData>();
            var listOldAlarm = new List<AlarmData>(listOld);

            foreach (var item in listOldAlarm)
            {
                if (!newAlarms.Any(n => n.PLCAdress == item.PLCAdress))
                {
                    item.EndTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                    canceledAlarms.Add(item);
                    listOld.Remove(item);
                }
            }

            return canceledAlarms;
        }

        /// <summary>
        /// 记录已取消的报警信息
        /// </summary>
        private void LogCanceledAlarms(List<AlarmData> canceledAlarms)
        {
            var nowDate = DateTime.Now;
            string basePath = $@"{CommonMethods.strAlarmLogspath}\{nowDate.Year}\{nowDate.Month}";
            string fileName = $@"{nowDate.Day}.csv";
            string title = "GUID,报警地址,故障代码,报警内容,开始时间,结束时间,是否停机";
            string alarmContent = string.Join("\n", canceledAlarms.Select(m1 =>
                $"{m1.AlarmGuid},{m1.PLCAdress},{m1.AlarmCode},{m1.AlarmContent},{m1.StartTime},{m1.EndTime},{m1.AlarmType}"));

            CSVHelper<AlarmCSVData>.WriterCSV(basePath, fileName, title, alarmContent);

            foreach (var m1 in canceledAlarms)
            {
                var alarm = new SysLog
                {
                    InsertTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                    LogType = "报警日志",
                    Note = m1.AlarmContent == "" ? m1.PLCAdress : m1.AlarmContent,
                    AlarmType = "错误",
                    Operater = CommonMethods.currentAdmin.LoginName,
                    VarName = m1.PLCAdress,
                    AlarmSet = "",
                    AlarmValue = "1",
                };
                // 显示报警信息
                CommonMethods.AddAlarmLog(alarm);
                // 报警top10保存
                SaveAlarmCount(canceledAlarms);
            }
        }

        /// <summary>
        /// 上传已取消的报警信息
        /// </summary>
        private async Task UploadCanceledAlarmsAsync(List<AlarmData> canceledAlarms, string strGuidAlarm)
        {
            if (CommonMethods.sysConfig.MesModeSwitching && CommonMethods.mesConfig.isConnected)
            {
                await CommonMethods.hbgMes.UploadEquAlarmAsync(
                    CommonMethods.mesConfig.DeviceAlarm,
                    CommonMethods.mesConfig.siteCode,
                    CommonMethods.mesConfig.lineCode,
                    CommonMethods.mesConfig.equipNum,
                    CommonMethods.mesConfig.MaterialCode,
                    CommonMethods.mesConfig.mesUserName,
                    canceledAlarms,
                    strGuidAlarm
                );
            }
        }


        /// <summary>
        /// 报警Top10保存
        /// </summary>
        private void SaveAlarmCount(List<AlarmData> alarmDatas)
        {
            bool ISAdd = false;
            var recordToUpdate = new AlarmCountEntry();

            DateTime today = DateTime.Today;
            DateTime upTime = DateTime.Now;
            var listAlarmStatistics = CommonMethods.db.QueryWhereList<AlarmCountEntry>(it => Convert.ToDateTime(it.AlarmTime.ToString("yyyy-MM-dd")) == today);
            List<AlarmCountEntry> fd = new List<AlarmCountEntry>();
            if (listAlarmStatistics != null)
            {
                alarmDatas.ForEach(r =>
                {
                    recordToUpdate = listAlarmStatistics.FirstOrDefault(x => x.PLCAdress.Trim() == r.PLCAdress);
                    if (recordToUpdate != null)
                    {
                        CommonMethods.db.Update<AlarmCountEntry>(it => it.AlarmCount == it.AlarmCount + 1, it => it.PLCAdress == r.PLCAdress && Convert.ToDateTime(it.AlarmTime.ToString("yyyy-MM-dd")) == today);
                    }
                    else
                    {
                        ISAdd = true;
                        AlarmCountEntry alarm = new AlarmCountEntry();
                        alarm.PLCAdress = r.PLCAdress;
                        alarm.AlarmContent = r.AlarmContent;
                        alarm.AlarmCount = 1;
                        alarm.Class = CommonMethods.strClass;
                        alarm.AlarmTime = upTime;
                        fd.Add(alarm);
                    }
                });
                if (ISAdd)
                {
                    bool res = CommonMethods.db.AddReturnBool(fd);
                    ISAdd = false;
                }
            }
            else
            {
                foreach (var m in listNew)
                {
                    AlarmCountEntry alarm = new AlarmCountEntry();
                    alarm.PLCAdress = m.PLCAdress;
                    alarm.AlarmContent = m.AlarmContent;
                    alarm.AlarmCount = 1;
                    alarm.Class = CommonMethods.strClass;
                    alarm.AlarmTime = today;
                    fd.Add(alarm);
                }
                CommonMethods.db.AddReturnBool(fd);
            }
            GetASqlAlarmData(DateTime.Today, CommonMethods.strClass);
        }


        /// <summary>
        /// 读取数据库报警信息
        /// </summary>
        /// <param name="today"></param>
        /// <param name="strClass"></param>
        public void GetASqlAlarmData(DateTime today, string strClass)
        {
            try
            {
                List<ChartDataType> chartAlarms = new List<ChartDataType>();
                List<AlarmCountEntry> AlarmDatas = null;
                List<string> List_X = new List<string>();
                List<int> List_Y = new List<int>();

                DateTime baiClassStart = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 8:30:00"));
                DateTime baiClassEnd = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 20:29:59"));

                DateTime yeClassStart = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 20:30:00"));
                DateTime yeClassEnd = Convert.ToDateTime(DateTime.Now.AddDays(1).ToString("yyyy-MM-dd 8:29:59"));


                if (strClass == "全天".Translated())
                {
                    AlarmDatas = CommonMethods.db.QueryList<AlarmCountEntry>("AlarmCount", 10, it => Convert.ToDateTime(it.AlarmTime.ToString("yyyy-MM-dd")) == today);
                }
                else if (strClass == "白班".Translated())
                {
                    AlarmDatas = CommonMethods.db.QueryList<AlarmCountEntry>("AlarmCount", 10, it => it.AlarmTime >= baiClassStart && it.AlarmTime <= baiClassEnd && it.Class == strClass);
                }
                else
                {
                    AlarmDatas = CommonMethods.db.QueryList<AlarmCountEntry>("AlarmCount", 10, it => it.AlarmTime >= yeClassStart && it.AlarmTime <= yeClassEnd && it.Class == strClass);
                }

                if (AlarmDatas != null && AlarmDatas.Count > 0)
                {

                    for (int i = 0; i < AlarmDatas.Count; i++)
                    {
                        chartAlarms.Add(new ChartDataType()
                        {
                            DataType = AlarmDatas[i].AlarmContent,
                            DataCount = (int)AlarmDatas[i].AlarmCount
                        });
                    }
                    CommonMethods.Lst_AlarmTop10_Qty = chartAlarms;
                }
                else
                {
                    CommonMethods.Lst_AlarmTop10_Qty = null;
                }
            }
            catch (Exception)
            {

            }
        }

        #endregion

        #region 下发权限给PLC
        /// <summary>
        /// 下发权限到PLC
        /// </summary>
        /// 
        private async Task SendRightToPLCAsync()
        {
            ushort quanxian = 1;
            switch (CommonMethods.currentAdmin.LoginLevel)
            {
                case "操作员":
                    quanxian = 1;
                    break;
                case "工程师":
                    quanxian = 2;
                    break;
                case "管理员":
                    quanxian = 3;
                    break;
                default:
                    break;
            }


            foreach (var plc in CommonMethods.plcDevices)
            {
                if (plcDeviceMapping.TryGetValue(plc, out var plcDevices))
                {
                    foreach (var plcDevice in plcDevices)
                    {
                        if (plcDevice.IsConnected)
                        {
                            JYResult result = await Task.Run(() => plc.WriteValue("D21", (short)quanxian, DataType.Short));
                            if (result.IsSuccess)
                            {
                                CommonMethods.AddDataMonitorLog(1, $"Write_PLC_permission_Successful");
                            }
                            else
                            {
                                CommonMethods.AddDataMonitorLog(2, $"Write_PLC_permission(D15)_Failed");
                            }
                        }
                    }
                }
            }
        }

        #endregion

        #region 获取白夜班次
        bool qiehuan = false;
        private void SetClass()
        {
            try
            {
                var nowDate = DateTime.Now;
                string strClass = "";
                DateTime time1 = Convert.ToDateTime($"{nowDate.ToShortDateString()} {CommonMethods.ChangeClassTime}");
                DateTime time2 = Convert.ToDateTime($"{nowDate.ToShortDateString()} {Convert.ToDateTime(CommonMethods.ChangeClassTime).AddHours(12).ToString("HH:mm:ss")}");
                if (nowDate <= time1 && nowDate >= time2)
                {
                    if (CommonMethods.plcDevices[0].IsConnected)
                    {
                        if (!qiehuan)
                        {
                            if (!SetPlcTime())
                            {
                                CommonMethods.AddLog(true, $"PC写入PLC时间失败".Translated());
                            }
                            else
                            {
                                qiehuan = true;
                                CommonMethods.AddLog(false, "PC写入PLC时间成功".Translated());
                            }
                        }
                    }
                    strClass = "白班".Translated();
                }
                else
                {
                    qiehuan = false;
                    strClass = "夜班".Translated();
                }
                CommonMethods.strClass = strClass;
            }
            catch (Exception ex)
            {
                CommonMethods.AddLog(true, "PC写入PLC时间异常".Translated() + ":" + ex.Message);
                LogHelper.Instance.WriteEX(ex);
            }
        }
        #endregion

        #region  写入PLC时间
        /// <summary>
        /// 写当前时间给PLC
        /// </summary>
        private bool SetPlcTime()
        {
            var nowDate = DateTime.Now;
            string yearStr = nowDate.Year.ToString();


            bool IsSuccess = false;

            // 为防止PLC时间出现偏差，每次自动运行的时候写PLC系统时间
            short[] writeArr = new short[]
            {
                Convert.ToInt16(nowDate.Year),//D70
                Convert.ToInt16(nowDate.Month),//D71
                Convert.ToInt16(nowDate.Day),//D72
                Convert.ToInt16(nowDate.Hour),//D73
                Convert.ToInt16(nowDate.Minute),//D74
                Convert.ToInt16(nowDate.Second),//D75
                (short)1 //D76
            };
            if (CommonMethods.plcDevices[0].IsConnected)
            {
                JYResult result = CommonMethods.plcDevices[0].WriteValue("D70", writeArr, DataType.ArrShort);
                if (result.IsSuccess)
                {
                    IsSuccess = true;
                }
            }
            return IsSuccess;

        }

        #region 8、IDisposable 实现


        // 如果需要在StopAsync中也显示进度，可以添加一个进度回调

        private Task processTask;

        public async Task StopAsync(IProgress<string> progress = null)
        {
            _cts.Cancel();

            if (_heartbeatTask != null)
            {
                progress?.Report("正在停止心跳任务...");
                try
                {
                    await _heartbeatTask;
                }
                catch (OperationCanceledException)
                {
                    // 忽略取消异常
                }
            }

            if (processTask != null)
            {
                progress?.Report("正在停止处理任务...");
                try
                {
                    await processTask;
                }
                catch (OperationCanceledException)
                {
                    // 忽略取消异常
                }
            }

            foreach (var pair in groupTasks)
            {
                progress?.Report($"正在停止组任务: {pair.Key}...");
                try
                {
                    await pair.Value;
                }
                catch (OperationCanceledException)
                {
                    // 忽略取消异常
                }
            }
        }



        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }


        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                _cts?.Cancel();
                _cts?.Dispose();

                processTask?.Wait();

                // 断开所有设备连接
                foreach (var plc in CommonMethods.plcDevices)
                {
                    plc.Disconnect();
                    if (plcAlarmReaders.TryGetValue(plc, out var alarmReader))
                    {
                        //alarmReader.PLCAlarm_New -= AlrmReader_PLCAlarm_New;
                        //alarmReader.PLCAlarm_Remove -= AlrmReader_PLCAlarm_Remove;
                    }
                }

                CommonMethods.plcDevices.Clear();
                plcDeviceMapping.Clear();
                plcAlarmReaders.Clear();
                CommonMethods.plcStatuses.Clear();

                DisconnectAllPlcs();
            }
        }



        #endregion
        #endregion

        #region 7、辅助方法

        private static PLCType GetPLCTypeEnum(string plcTypeString)
        {
            if (Enum.TryParse(plcTypeString, out PLCType plcType))
            {
                return plcType;
            }
            throw new ArgumentException($"PLC 类型无效: {plcTypeString}");
        }



        #endregion

        #region 8、轴/电机位置监控
        private void ReadAxleCSV(int flag, ref List<AxleLog> axleLog, ref List<MotorLog> motorLog)
        {
            axleLog = new List<AxleLog>();
            motorLog = new List<MotorLog>();
            try
            {
                string strLine = "";
                string[] csvReset;//轴位置暂存
                string PlcAddress = string.Empty;
                bool isExits = false;
                switch (flag)
                {
                    case 1://本机轴设定位置
                        IniConfigHelper.CreateIniFile(configFolderPath, "Motor_YiCiWaiGuanAxle.ini");
                        if (!File.Exists(Path.Combine(configFolderPath, "Motor_YiCiWaiGuanAxle.ini")))//判断ini文件是否存在
                        {
                            isExits = true;
                        }
                        using (StreamReader reader = new StreamReader(Path.Combine(configFolderPath, "Motor_YiCiWaiGuanAxle.csv"), System.Text.Encoding.GetEncoding("GB2312")))
                        {
                            while ((strLine = reader.ReadLine()) != null)
                            {
                                csvReset = strLine.Split(',', '[', ']');
                                if (csvReset.Length != 5 && csvReset[0] == "")
                                {
                                    continue;
                                }
                                if (string.IsNullOrEmpty(csvReset[4]) || string.IsNullOrWhiteSpace(csvReset[4]))
                                {
                                    break; // 空地址跳出读取
                                }
                                PlcAddress = csvReset[4];
                                AxleLog axle = new AxleLog();
                                axle.m_AxleDscribe = csvReset[0] + csvReset[1];
                                axle.m_AxleLocation = csvReset[3];
                                axle.m_AxleAddress = PlcAddress;
                                axleLog.Add(axle);
                                if (isExits)
                                {
                                    string Value = CommonMethods.plcDevices[0].ReadFloat(PlcAddress).ToString();
                                    IniConfigHelper.WriteIniData(axle.m_AxleDscribe, axle.m_AxleLocation, Value, Path.Combine(configFolderPath, "Motor_YiCiWaiGuanAxle.ini"));
                                }
                            }
                            reader.Close();
                            reader.Dispose();
                        }
                        break;
                    case 2://本机电机位置设定值motor
                        IniConfigHelper.CreateIniFile(configFolderPath, "Motor_YiCiWaiGuanMotor.ini");
                        if (!File.Exists(Path.Combine(configFolderPath, "Motor_YiCiWaiGuanMotor.ini")))//判断ini文件是否存在
                        {
                            isExits = true;
                        }
                        using (StreamReader reader = new StreamReader(Path.Combine(configFolderPath, "Motor_YiCiWaiGuanMotor.csv"), System.Text.Encoding.GetEncoding("GB2312")))
                        {
                            while ((strLine = reader.ReadLine()) != null)
                            {
                                csvReset = strLine.Split(',', '[', ']');
                                if (csvReset.Length != 5 && csvReset[0] == "")
                                {
                                    continue;
                                }
                                if (string.IsNullOrEmpty(csvReset[4]) || string.IsNullOrWhiteSpace(csvReset[4]))
                                {
                                    break; // 空地址跳出读取
                                }
                                PlcAddress = csvReset[4];
                                MotorLog motor = new MotorLog();
                                motor.m_MotorDscribe = csvReset[0] + csvReset[1];
                                motor.m_MotorLocation = csvReset[3];
                                motor.m_MotorAddress = PlcAddress;
                                motorLog.Add(motor);
                                if (isExits)
                                {
                                    string Value = CommonMethods.plcDevices[0].ReadFloat(PlcAddress).ToString();
                                    IniConfigHelper.WriteIniData(motor.m_MotorDscribe, motor.m_MotorLocation, Value, Path.Combine(configFolderPath, "Motor_YiCiWaiGuanMotor.ini"));
                                }
                            }
                            reader.Close();
                            reader.Dispose();
                        }
                        break;
                    default: break;
                }

            }
            catch (Exception ex)
            {
                axleLog = null;
                motorLog = null;
                LogHelper.Instance.WriteError($"轴/电机位置读取配置文件错误：{ex}", "SysErrorLog");
            }
        }



        /// <summary>轴/电机对象集合
        /// 
        /// </summary>
        private static List<MotorLog> motorLog = new List<MotorLog>();
        private static List<AxleLog> axleLog = new List<AxleLog>();
        private static Stopwatch swtest = new Stopwatch();

        /// <summary>
        ///  监控轴位置变化
        /// </summary>
        public void ShowAxleEven_Run()
        {
            try
            {
                while (true)
                {
                    if (CommonMethods.plcDevices[0] != null && CommonMethods.plcDevices[0].IsConnected)
                    {
                        short nowPLCstate = CommonMethods.plcDevices[0].ReadInt16("D10");
                        if (nowPLCstate != 1)
                        {
                            if (axleLog.Count < 1)//|| motorLog.Count < 1
                            {
                                Thread.Sleep(1500);
                                ReadAxleCSV(1, ref axleLog, ref motorLog);//轴位置csv文件不存在，out axlelog=null，导致下次判断axlelog.Count报错（未将对象引用设置到对象实例）
                                Thread.Sleep(1500);
                            }
                            else
                            {
                                try
                                {
                                    // 第二种写法一次读出来
                                    swtest.Restart();
                                    JYResult<byte[]> resByte = CommonMethods.plcDevices[0].ReadValue<JYResult<byte[]>>($"{axleLog[0].m_AxleAddress}", DataType.ArrByte, Convert.ToUInt16(axleLog.Count * 4));
                                    swtest.Stop();
                                    long tempswt = swtest.ElapsedMilliseconds;

                                    swtest.Restart();
                                    if (resByte != null && resByte.IsSuccess && resByte.Content != null)
                                    {
                                        string AxleUpLocationOld;
                                        string AxleUpLocationNew;
                                        for (int i = 0; i < axleLog.Count; i++)
                                        {
                                            double NewCurrent = FloatLib.GetFloatFromByteArray(resByte.Content, i * 4); //D23000 起
                                            AxleUpLocationOld = IniConfigHelper.ReadIniData(axleLog[i].m_AxleDscribe, axleLog[i].m_AxleLocation, "0", Path.Combine(configFolderPath, "Motor_YiCiWaiGuanAxle.ini"));
                                            AxleUpLocationNew = Math.Round(NewCurrent, 2).ToString();
                                            if (AxleUpLocationNew != AxleUpLocationOld)
                                            {
                                                string AlterTime = DateTime.Now.ToString("yyyy-MM-dd_HH:mm:ss.fff");
                                                //日期时间,电机描述,位置描述,位置修改前,当前位置
                                                LogHelper.PrintMotorLog.LogInfo(AlterTime, axleLog[i].m_AxleDscribe, axleLog[i].m_AxleLocation, AxleUpLocationOld, AxleUpLocationNew);
                                                IniConfigHelper.WriteIniData(axleLog[i].m_AxleDscribe, axleLog[i].m_AxleLocation, AxleUpLocationNew, Path.Combine(configFolderPath, "Motor_YiCiWaiGuanAxle.ini"));
                                            }
                                        }
                                    }
                                    swtest.Stop();
                                    tempswt = swtest.ElapsedMilliseconds;
                                }
                                catch (Exception ex)
                                {
                                    LogHelper.Instance.WriteError($"轴位置监控线程错误：{ex}", "SysErrorLog");
                                }
                            }
                        }
                    }
                    else { Thread.Sleep(5000); }
                    Thread.Sleep(1000);
                }
            }
            catch (Exception ex)
            {
                LogHelper.Instance.WriteError($"轴位置监控线程错误：{ex}", "SysErrorLog");
            }
        }

        /// <summary>
        ///  监控电机位置变化 取消
        /// </summary>
        public void ShowMotorEven_Run()
        {
            try
            {
                while (true)
                {
                    if (CommonMethods.plcDevices[0] != null && CommonMethods.plcDevices[0].IsConnected)
                    {
                        short nowPLCstate = CommonMethods.plcDevices[0].ReadInt16("D10");
                        if (nowPLCstate != 1)
                        {
                            if (axleLog.Count < 1 || motorLog.Count < 1)
                            {
                                Thread.Sleep(3000);
                                ReadAxleCSV(2, ref axleLog, ref motorLog);//电机位置csv文件不存在，out axlelog=null，导致下次判断axlelog.Count报错（未将对象引用设置到对象实例）
                                Thread.Sleep(1500);
                            }
                            else
                            {
                                try
                                {
                                    // 第二种写法一次读出来
                                    swtest.Restart();
                                    JYResult<byte[]> resByte = CommonMethods.plcDevices[0].ReadValue<JYResult<byte[]>>($"{motorLog[0].m_MotorAddress}", DataType.ArrByte, Convert.ToUInt16(motorLog.Count * 4));
                                    swtest.Stop();
                                    long tempswt = swtest.ElapsedMilliseconds;

                                    swtest.Restart();
                                    if (resByte != null && resByte.IsSuccess && resByte.Content != null)
                                    {
                                        string MotorUpLocationOld;
                                        string MotorUpLocationNew;
                                        for (int i = 0; i < motorLog.Count; i++)
                                        {
                                            double NewCurrent = FloatLib.GetFloatFromByteArray(resByte.Content, i * 4); //D23000 起
                                            MotorUpLocationOld = IniConfigHelper.ReadIniData(motorLog[i].m_MotorDscribe, motorLog[i].m_MotorLocation, "0", Path.Combine(configFolderPath, "Motor_YiCiWaiGuanAxle.ini"));
                                            MotorUpLocationNew = Math.Round(NewCurrent, 2).ToString();
                                            if (MotorUpLocationNew != MotorUpLocationOld)
                                            {
                                                string AlterTime = DateTime.Now.ToString("yyyy-MM-dd_HH:mm:ss.fff");
                                                //日期时间,电机描述,位置描述,位置修改前,当前位置
                                                LogHelper.PrintMotorLog.LogInfo(AlterTime, motorLog[i].m_MotorDscribe, motorLog[i].m_MotorLocation, MotorUpLocationOld, MotorUpLocationNew);
                                                IniConfigHelper.WriteIniData(motorLog[i].m_MotorDscribe, motorLog[i].m_MotorLocation, MotorUpLocationNew, Path.Combine(configFolderPath, "Motor_YiCiWaiGuanAxle.ini"));
                                            }
                                        }
                                    }
                                    swtest.Stop();
                                    tempswt = swtest.ElapsedMilliseconds;
                                }
                                catch (Exception ex)
                                {
                                    LogHelper.Instance.WriteError($"电机位置监控线程错误：{ex}", "SysErrorLog");
                                }
                            }
                        }
                    }
                    else { Thread.Sleep(5000); }
                    Thread.Sleep(1000);
                }
            }
            catch (Exception ex)
            {
                LogHelper.Instance.WriteError($"电机位置监控线程错误：{ex}", "SysErrorLog");
            }
        }
        #endregion
    }
}
